// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License

#pragma once

#ifdef __cplusplus

#define ARDUINOJSON_VERSION "5.13.5"
#define ARDUINOJSON_VERSION_MAJOR 5
#define ARDUINOJSON_VERSION_MINOR 13
#define ARDUINOJSON_VERSION_REVISION 5
#include <stddef.h>  // for size_t
#include <stdint.h>  // for uint8_t
#include <string.h>
namespace ArduinoJson {
    namespace Internals {
        class NonCopyable {
        protected:
            NonCopyable() {}
        private:
            NonCopyable(const NonCopyable&);
            NonCopyable& operator=(const NonCopyable&);
        };
    }  // namespace Internals
}  // namespace ArduinoJson
#ifndef ARDUINOJSON_EMBEDDED_MODE
#if defined(ARDUINO) || defined(__IAR_SYSTEMS_ICC__) || defined(__XC) || \
    defined(__ARMCC_VERSION)
#define ARDUINOJSON_EMBEDDED_MODE 1
#else
#define ARDUINOJSON_EMBEDDED_MODE 0
#endif
#endif
#if ARDUINOJSON_EMBEDDED_MODE
#ifndef ARDUINOJSON_USE_DOUBLE
#define ARDUINOJSON_USE_DOUBLE 0
#endif
#ifndef ARDUINOJSON_USE_LONG_LONG
#define ARDUINOJSON_USE_LONG_LONG 0
#endif
#ifndef ARDUINOJSON_USE_INT64
#define ARDUINOJSON_USE_INT64 0
#endif
#ifndef ARDUINOJSON_ENABLE_STD_STRING
#define ARDUINOJSON_ENABLE_STD_STRING 0
#endif
#ifndef ARDUINOJSON_ENABLE_STD_STREAM
#define ARDUINOJSON_ENABLE_STD_STREAM 0
#endif
#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
#endif
#else  // ARDUINOJSON_EMBEDDED_MODE
#ifndef ARDUINOJSON_USE_DOUBLE
#define ARDUINOJSON_USE_DOUBLE 1
#endif
#ifndef ARDUINOJSON_USE_LONG_LONG
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)
#define ARDUINOJSON_USE_LONG_LONG 1
#else
#define ARDUINOJSON_USE_LONG_LONG 0
#endif
#endif
#ifndef ARDUINOJSON_USE_INT64
#if defined(_MSC_VER) && _MSC_VER <= 1700
#define ARDUINOJSON_USE_INT64 1
#else
#define ARDUINOJSON_USE_INT64 0
#endif
#endif
#ifndef ARDUINOJSON_ENABLE_STD_STRING
#define ARDUINOJSON_ENABLE_STD_STRING 1
#endif
#ifndef ARDUINOJSON_ENABLE_STD_STREAM
#define ARDUINOJSON_ENABLE_STD_STREAM 1
#endif
#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 50
#endif
#endif  // ARDUINOJSON_EMBEDDED_MODE
#ifdef ARDUINO
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
#endif
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
#endif
#else  // ARDUINO
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
#endif
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
#endif
#endif  // ARDUINO
#ifndef ARDUINOJSON_ENABLE_PROGMEM
#ifdef PROGMEM
#define ARDUINOJSON_ENABLE_PROGMEM 1
#else
#define ARDUINOJSON_ENABLE_PROGMEM 0
#endif
#endif
#ifndef ARDUINOJSON_ENABLE_ALIGNMENT
#ifdef ARDUINO_ARCH_AVR
#define ARDUINOJSON_ENABLE_ALIGNMENT 0
#else
#define ARDUINOJSON_ENABLE_ALIGNMENT 1
#endif
#endif
#ifndef ARDUINOJSON_ENABLE_DEPRECATED
#define ARDUINOJSON_ENABLE_DEPRECATED 1
#endif
#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
#define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7
#endif
#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD
#define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5
#endif
#if ARDUINOJSON_USE_LONG_LONG && ARDUINOJSON_USE_INT64
#error ARDUINOJSON_USE_LONG_LONG and ARDUINOJSON_USE_INT64 cannot be set together
#endif
namespace ArduinoJson {
    namespace Internals {
#if ARDUINOJSON_USE_DOUBLE
        typedef double JsonFloat;
#else
        typedef float JsonFloat;
#endif
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
#if ARDUINOJSON_USE_LONG_LONG
        typedef long long JsonInteger;
        typedef unsigned long long JsonUInt;
#elif ARDUINOJSON_USE_INT64
        typedef __int64 JsonInteger;
        typedef unsigned _int64 JsonUInt;
#else
        typedef long JsonInteger;
        typedef unsigned long JsonUInt;
#endif
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    class JsonArray;
    class JsonObject;
    namespace Internals {
        union JsonVariantContent {
            JsonFloat asFloat;     // used for double and float
            JsonUInt asInteger;    // used for bool, char, short, int and longs
            const char* asString;  // asString can be null
            JsonArray* asArray;    // asArray cannot be null
            JsonObject* asObject;  // asObject cannot be null
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        struct JsonVariantDefault {
            static T get() {
                return T();
            }
        };
        template <typename T>
        struct JsonVariantDefault<const T> : JsonVariantDefault<T> {};
        template <typename T>
        struct JsonVariantDefault<T&> : JsonVariantDefault<T> {};
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    class JsonArray;
    class JsonObject;
    namespace Internals {
        enum JsonVariantType {
            JSON_UNDEFINED,         // JsonVariant has not been initialized
            JSON_UNPARSED,          // JsonVariant contains an unparsed string
            JSON_STRING,            // JsonVariant stores a const char*
            JSON_BOOLEAN,           // JsonVariant stores a bool
            JSON_POSITIVE_INTEGER,  // JsonVariant stores an JsonUInt
            JSON_NEGATIVE_INTEGER,  // JsonVariant stores an JsonUInt that must be negated
            JSON_ARRAY,             // JsonVariant stores a pointer to a JsonArray
            JSON_OBJECT,            // JsonVariant stores a pointer to a JsonObject
            JSON_FLOAT              // JsonVariant stores a JsonFloat
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        struct JsonVariantAs {
            typedef T type;
        };
        template <>
        struct JsonVariantAs<char*> {
            typedef const char* type;
        };
        template <>
        struct JsonVariantAs<JsonArray> {
            typedef JsonArray& type;
        };
        template <>
        struct JsonVariantAs<const JsonArray> {
            typedef const JsonArray& type;
        };
        template <>
        struct JsonVariantAs<JsonObject> {
            typedef JsonObject& type;
        };
        template <>
        struct JsonVariantAs<const JsonObject> {
            typedef const JsonObject& type;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
#ifdef _MSC_VER  // Visual Studio
#define FORCE_INLINE  // __forceinline causes C4714 when returning std::string
#define NO_INLINE __declspec(noinline)
#define DEPRECATED(msg) __declspec(deprecated(msg))
#elif defined(__GNUC__)  // GCC or Clang
#define FORCE_INLINE __attribute__((always_inline))
#define NO_INLINE __attribute__((noinline))
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
#define DEPRECATED(msg) __attribute__((deprecated(msg)))
#else
#define DEPRECATED(msg) __attribute__((deprecated))
#endif
#else  // Other compilers
#define FORCE_INLINE
#define NO_INLINE
#define DEPRECATED(msg)
#endif
namespace ArduinoJson {
    namespace Internals {
        template <typename TImpl>
        class JsonVariantCasts {
        public:
#if ARDUINOJSON_ENABLE_DEPRECATED
            DEPRECATED("use as<JsonArray>() instead")
                FORCE_INLINE JsonArray &asArray() const {
                return impl()->template as<JsonArray>();
            }
            DEPRECATED("use as<JsonObject>() instead")
                FORCE_INLINE JsonObject &asObject() const {
                return impl()->template as<JsonObject>();
            }
            DEPRECATED("use as<char*>() instead")
                FORCE_INLINE const char *asString() const {
                return impl()->template as<const char *>();
            }
#endif
            FORCE_INLINE operator JsonArray &() const {
                return impl()->template as<JsonArray &>();
            }
            FORCE_INLINE operator JsonObject &() const {
                return impl()->template as<JsonObject &>();
            }
            template <typename T>
            FORCE_INLINE operator T() const {
                return impl()->template as<T>();
            }
        private:
            const TImpl *impl() const {
                return static_cast<const TImpl *>(this);
            }
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <bool Condition, typename T = void>
        struct EnableIf {};
        template <typename T>
        struct EnableIf<true, T> {
            typedef T type;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename TBase, typename TDerived>
        class IsBaseOf {
        protected:  // <- to avoid GCC's "all member functions in class are private"
            typedef char Yes[1];
            typedef char No[2];
            static Yes &probe(const TBase *);
            static No &probe(...);
        public:
            enum {
                value = sizeof(probe(reinterpret_cast<TDerived *>(0))) == sizeof(Yes)
            };
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T, typename U>
        struct IsSame {
            static const bool value = false;
        };
        template <typename T>
        struct IsSame<T, T> {
            static const bool value = true;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        struct IsChar {
            static const bool value = IsSame<T, char>::value ||
                IsSame<T, signed char>::value ||
                IsSame<T, unsigned char>::value;
        };
        template <typename T>
        struct IsChar<const T> : IsChar<T> {};
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        struct IsConst {
            static const bool value = false;
        };
        template <typename T>
        struct IsConst<const T> {
            static const bool value = true;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        struct RemoveReference {
            typedef T type;
        };
        template <typename T>
        struct RemoveReference<T&> {
            typedef T type;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename TString, typename Enable = void>
        struct StringTraits {
            static const bool has_append = false;
            static const bool has_equals = false;
        };
        template <typename TString>
        struct StringTraits<const TString, void> : StringTraits<TString> {};
        template <typename TString>
        struct StringTraits<TString&, void> : StringTraits<TString> {};
    }  // namespace Internals
}  // namespace ArduinoJson
#if ARDUINOJSON_ENABLE_ARDUINO_STREAM
#include <Stream.h>
namespace ArduinoJson {
    namespace Internals {
        struct ArduinoStreamTraits {
            class Reader {
                Stream& _stream;
                char _current, _next;
            public:
                Reader(Stream& stream) : _stream(stream), _current(0), _next(0) {}
                void move() {
                    _current = _next;
                    _next = 0;
                }
                char current() {
                    if (!_current) _current = read();
                    return _current;
                }
                char next() {
                    if (!_next) _next = read();
                    return _next;
                }
            private:
                char read() {
                    char c = 0;
                    _stream.readBytes(&c, 1);
                    return c;
                }
            };
            static const bool has_append = false;
            static const bool has_equals = false;
        };
        template <typename TStream>
        struct StringTraits<
            TStream,
            typename EnableIf<
            IsBaseOf<Stream, typename RemoveReference<TStream>::type>::value>::type>
            : ArduinoStreamTraits {};
    }  // namespace Internals
}  // namespace ArduinoJson
#endif
namespace ArduinoJson {
    namespace Internals {
        template <typename TChar>
        struct CharPointerTraits {
            class Reader {
                const TChar* _ptr;
            public:
                Reader(const TChar* ptr)
                    : _ptr(ptr ? ptr : reinterpret_cast<const TChar*>("")) {}
                void move() {
                    ++_ptr;
                }
                char current() const {
                    return char(_ptr[0]);
                }
                char next() const {
                    return char(_ptr[1]);
                }
            };
            static bool equals(const TChar* str, const char* expected) {
                const char* actual = reinterpret_cast<const char*>(str);
                if (!actual || !expected) return actual == expected;
                return strcmp(actual, expected) == 0;
            }
            static bool is_null(const TChar* str) {
                return !str;
            }
            typedef const char* duplicate_t;
            template <typename Buffer>
            static duplicate_t duplicate(const TChar* str, Buffer* buffer) {
                if (!str) return NULL;
                size_t size = strlen(reinterpret_cast<const char*>(str)) + 1;
                void* dup = buffer->alloc(size);
                if (dup != NULL) memcpy(dup, str, size);
                return static_cast<duplicate_t>(dup);
            }
            static const bool has_append = false;
            static const bool has_equals = true;
            static const bool should_duplicate = !IsConst<TChar>::value;
        };
        template <typename TChar>
        struct StringTraits<TChar*, typename EnableIf<IsChar<TChar>::value>::type>
            : CharPointerTraits<TChar> {};
    }  // namespace Internals
}  // namespace ArduinoJson
#if ARDUINOJSON_ENABLE_PROGMEM
namespace ArduinoJson {
    namespace Internals {
        template <>
        struct StringTraits<const __FlashStringHelper*, void> {
            class Reader {
                const char* _ptr;
            public:
                Reader(const __FlashStringHelper* ptr)
                    : _ptr(reinterpret_cast<const char*>(ptr)) {}
                void move() {
                    _ptr++;
                }
                char current() const {
                    return pgm_read_byte_near(_ptr);
                }
                char next() const {
                    return pgm_read_byte_near(_ptr + 1);
                }
            };
            static bool equals(const __FlashStringHelper* str, const char* expected) {
                const char* actual = reinterpret_cast<const char*>(str);
                if (!actual || !expected) return actual == expected;
                return strcmp_P(expected, actual) == 0;
            }
            static bool is_null(const __FlashStringHelper* str) {
                return !str;
            }
            typedef const char* duplicate_t;
            template <typename Buffer>
            static duplicate_t duplicate(const __FlashStringHelper* str, Buffer* buffer) {
                if (!str) return NULL;
                size_t size = strlen_P((const char*)str) + 1;
                void* dup = buffer->alloc(size);
                if (dup != NULL) memcpy_P(dup, (const char*)str, size);
                return static_cast<duplicate_t>(dup);
            }
            static const bool has_append = false;
            static const bool has_equals = true;
            static const bool should_duplicate = true;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
#endif
#if ARDUINOJSON_ENABLE_STD_STREAM
#include <istream>
namespace ArduinoJson {
    namespace Internals {
        struct StdStreamTraits {
            class Reader {
                std::istream& _stream;
                char _current, _next;
            public:
                Reader(std::istream& stream) : _stream(stream), _current(0), _next(0) {}
                void move() {
                    _current = _next;
                    _next = 0;
                }
                char current() {
                    if (!_current) _current = read();
                    return _current;
                }
                char next() {
                    if (!_next) _next = read();
                    return _next;
                }
            private:
                Reader& operator=(const Reader&);  // Visual Studio C4512
                char read() {
                    return _stream.eof() ? '\0' : static_cast<char>(_stream.get());
                }
            };
            static const bool has_append = false;
            static const bool has_equals = false;
        };
        template <typename TStream>
        struct StringTraits<
            TStream,
            typename EnableIf<IsBaseOf<
            std::istream, typename RemoveReference<TStream>::type>::value>::type>
            : StdStreamTraits {};
    }  // namespace Internals
}  // namespace ArduinoJson
#endif
#if ARDUINOJSON_ENABLE_STD_STRING || ARDUINOJSON_ENABLE_ARDUINO_STRING
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <WString.h>
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
#include <string>
#endif
namespace ArduinoJson {
    namespace Internals {
        template <typename TString>
        struct StdStringTraits {
            typedef const char* duplicate_t;
            template <typename Buffer>
            static duplicate_t duplicate(const TString& str, Buffer* buffer) {
                if (!str.c_str()) return NULL;  // <- Arduino string can return NULL
                size_t size = str.length() + 1;
                void* dup = buffer->alloc(size);
                if (dup != NULL) memcpy(dup, str.c_str(), size);
                return static_cast<duplicate_t>(dup);
            }
            static bool is_null(const TString& str) {
                return !str.c_str();
            }
            struct Reader : CharPointerTraits<char>::Reader {
                Reader(const TString& str) : CharPointerTraits<char>::Reader(str.c_str()) {}
            };
            static bool equals(const TString& str, const char* expected) {
                const char* actual = str.c_str();
                if (!actual || !expected) return actual == expected;
                return 0 == strcmp(actual, expected);
            }
            static void append(TString& str, char c) {
                str += c;
            }
            static void append(TString& str, const char* s) {
                str += s;
            }
            static const bool has_append = true;
            static const bool has_equals = true;
            static const bool should_duplicate = true;
        };
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
        template <>
        struct StringTraits<String, void> : StdStringTraits<String> {};
        template <>
        struct StringTraits<StringSumHelper, void> : StdStringTraits<StringSumHelper> {
        };
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
        template <>
        struct StringTraits<std::string, void> : StdStringTraits<std::string> {};
#endif
    }  // namespace Internals
}  // namespace ArduinoJson
#endif
namespace ArduinoJson {
    namespace Internals {
        class JsonVariantTag {};
        template <typename T>
        struct IsVariant : IsBaseOf<JsonVariantTag, T> {};
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename TImpl>
        class JsonVariantComparisons {
        public:
            template <typename TComparand>
            friend bool operator==(const JsonVariantComparisons &variant,
                TComparand comparand) {
                return variant.equals(comparand);
            }
            template <typename TComparand>
            friend typename EnableIf<!IsVariant<TComparand>::value, bool>::type
                operator==(TComparand comparand, const JsonVariantComparisons &variant) {
                return variant.equals(comparand);
            }
            template <typename TComparand>
            friend bool operator!=(const JsonVariantComparisons &variant,
                TComparand comparand) {
                return !variant.equals(comparand);
            }
            template <typename TComparand>
            friend typename EnableIf<!IsVariant<TComparand>::value, bool>::type
                operator!=(TComparand comparand, const JsonVariantComparisons &variant) {
                return !variant.equals(comparand);
            }
            template <typename TComparand>
            friend bool operator<=(const JsonVariantComparisons &left, TComparand right) {
                return left.as<TComparand>() <= right;
            }
            template <typename TComparand>
            friend bool operator<=(TComparand comparand,
                const JsonVariantComparisons &variant) {
                return comparand <= variant.as<TComparand>();
            }
            template <typename TComparand>
            friend bool operator>=(const JsonVariantComparisons &variant,
                TComparand comparand) {
                return variant.as<TComparand>() >= comparand;
            }
            template <typename TComparand>
            friend bool operator>=(TComparand comparand,
                const JsonVariantComparisons &variant) {
                return comparand >= variant.as<TComparand>();
            }
            template <typename TComparand>
            friend bool operator<(const JsonVariantComparisons &varian,
                TComparand comparand) {
                return varian.as<TComparand>() < comparand;
            }
            template <typename TComparand>
            friend bool operator<(TComparand comparand,
                const JsonVariantComparisons &variant) {
                return comparand < variant.as<TComparand>();
            }
            template <typename TComparand>
            friend bool operator>(const JsonVariantComparisons &variant,
                TComparand comparand) {
                return variant.as<TComparand>() > comparand;
            }
            template <typename TComparand>
            friend bool operator>(TComparand comparand,
                const JsonVariantComparisons &variant) {
                return comparand > variant.as<TComparand>();
            }
        private:
            const TImpl *impl() const {
                return static_cast<const TImpl *>(this);
            }
            template <typename T>
            const typename JsonVariantAs<T>::type as() const {
                return impl()->template as<T>();
            }
            template <typename T>
            bool is() const {
                return impl()->template is<T>();
            }
            template <typename TString>
            typename EnableIf<StringTraits<TString>::has_equals, bool>::type equals(
                const TString &comparand) const {
                const char *value = as<const char *>();
                return StringTraits<TString>::equals(comparand, value);
            }
            template <typename TComparand>
            typename EnableIf<!IsVariant<TComparand>::value &&
                !StringTraits<TComparand>::has_equals,
                bool>::type
                equals(const TComparand &comparand) const {
                return as<TComparand>() == comparand;
            }
            template <typename TVariant2>
            bool equals(const JsonVariantComparisons<TVariant2> &right) const {
                using namespace Internals;
                if (is<bool>() && right.template is<bool>())
                    return as<bool>() == right.template as<bool>();
                if (is<JsonInteger>() && right.template is<JsonInteger>())
                    return as<JsonInteger>() == right.template as<JsonInteger>();
                if (is<JsonFloat>() && right.template is<JsonFloat>())
                    return as<JsonFloat>() == right.template as<JsonFloat>();
                if (is<JsonArray>() && right.template is<JsonArray>())
                    return as<JsonArray>() == right.template as<JsonArray>();
                if (is<JsonObject>() && right.template is<JsonObject>())
                    return as<JsonObject>() == right.template as<JsonObject>();
                if (is<char *>() && right.template is<char *>())
                    return StringTraits<const char *>::equals(as<char *>(),
                        right.template as<char *>());
                return false;
            }
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        struct IsSignedIntegral {
            static const bool value =
                IsSame<T, signed char>::value || IsSame<T, signed short>::value ||
                IsSame<T, signed int>::value || IsSame<T, signed long>::value ||
#if ARDUINOJSON_USE_LONG_LONG
                IsSame<T, signed long long>::value ||
#endif
#if ARDUINOJSON_USE_INT64
                IsSame<T, signed __int64>::value ||
#endif
                false;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        struct IsUnsignedIntegral {
            static const bool value =
                IsSame<T, unsigned char>::value || IsSame<T, unsigned short>::value ||
                IsSame<T, unsigned int>::value || IsSame<T, unsigned long>::value ||
#if ARDUINOJSON_USE_LONG_LONG
                IsSame<T, unsigned long long>::value ||
#endif
#if ARDUINOJSON_USE_INT64
                IsSame<T, unsigned __int64>::value ||
#endif
                false;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        struct IsIntegral {
            static const bool value = IsSignedIntegral<T>::value ||
                IsUnsignedIntegral<T>::value ||
                IsSame<T, char>::value;
        };
        template <typename T>
        struct IsIntegral<const T> : IsIntegral<T> {};
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename TImpl>
        class JsonVariantOr {
        public:
            template <typename T>
            typename EnableIf<!IsIntegral<T>::value, T>::type operator|(
                const T &defaultValue) const {
                if (impl()->template is<T>())
                    return impl()->template as<T>();
                else
                    return defaultValue;
            }
            const char *operator|(const char *defaultValue) const {
                const char *value = impl()->template as<const char *>();
                return value ? value : defaultValue;
            }
            template <typename Integer>
            typename EnableIf<IsIntegral<Integer>::value, Integer>::type operator|(
                const Integer &defaultValue) const {
                if (impl()->template is<double>())
                    return impl()->template as<Integer>();
                else
                    return defaultValue;
            }
        private:
            const TImpl *impl() const {
                return static_cast<const TImpl *>(this);
            }
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        class JsonArraySubscript;
        template <typename TKey>
        class JsonObjectSubscript;
        template <typename TImpl>
        class JsonVariantSubscripts {
        public:
            size_t size() const {
                return impl()->template as<JsonArray>().size() +
                    impl()->template as<JsonObject>().size();
            }
            FORCE_INLINE const JsonArraySubscript operator[](size_t index) const;
            FORCE_INLINE JsonArraySubscript operator[](size_t index);
            template <typename TString>
            FORCE_INLINE
                typename EnableIf<StringTraits<TString>::has_equals,
                const JsonObjectSubscript<const TString &> >::type
                operator[](const TString &key) const {
                return impl()->template as<JsonObject>()[key];
            }
            template <typename TString>
            FORCE_INLINE typename EnableIf<StringTraits<TString>::has_equals,
                JsonObjectSubscript<const TString &> >::type
                operator[](const TString &key) {
                return impl()->template as<JsonObject>()[key];
            }
            template <typename TString>
            FORCE_INLINE typename EnableIf<StringTraits<const TString *>::has_equals,
                JsonObjectSubscript<const TString *> >::type
                operator[](const TString *key) {
                return impl()->template as<JsonObject>()[key];
            }
            template <typename TString>
            FORCE_INLINE
                typename EnableIf<StringTraits<TString *>::has_equals,
                const JsonObjectSubscript<const TString *> >::type
                operator[](const TString *key) const {
                return impl()->template as<JsonObject>()[key];
            }
        private:
            const TImpl *impl() const {
                return static_cast<const TImpl *>(this);
            }
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        class DummyPrint {
        public:
            size_t print(char) {
                return 1;
            }
            size_t print(const char* s) {
                return strlen(s);
            }
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename TString>
        class DynamicStringBuilder {
        public:
            DynamicStringBuilder(TString &str) : _str(str) {}
            size_t print(char c) {
                StringTraits<TString>::append(_str, c);
                return 1;
            }
            size_t print(const char *s) {
                size_t initialLen = _str.length();
                StringTraits<TString>::append(_str, s);
                return _str.length() - initialLen;
            }
        private:
            DynamicStringBuilder &operator=(const DynamicStringBuilder &);
            TString &_str;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename Print>
        class IndentedPrint {
        public:
            explicit IndentedPrint(Print &p) : sink(&p) {
                level = 0;
                tabSize = 2;
                isNewLine = true;
            }
            size_t print(char c) {
                size_t n = 0;
                if (isNewLine) n += writeTabs();
                n += sink->print(c);
                isNewLine = c == '\n';
                return n;
            }
            size_t print(const char *s) {
                size_t n = 0;
                while (*s) n += print(*s++);
                return n;
            }
            void indent() {
                if (level < MAX_LEVEL) level++;
            }
            void unindent() {
                if (level > 0) level--;
            }
            void setTabSize(uint8_t n) {
                if (n < MAX_TAB_SIZE) tabSize = n & MAX_TAB_SIZE;
            }
        private:
            Print *sink;
            uint8_t level : 4;
            uint8_t tabSize : 3;
            bool isNewLine : 1;
            size_t writeTabs() {
                size_t n = 0;
                for (int i = 0; i < level * tabSize; i++) n += sink->print(' ');
                return n;
            }
            static const int MAX_LEVEL = 15;    // because it's only 4 bits
            static const int MAX_TAB_SIZE = 7;  // because it's only 3 bits
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        class Encoding {
        public:
            static char escapeChar(char c) {
                const char *p = escapeTable(false);
                while (p[0] && p[1] != c) {
                    p += 2;
                }
                return p[0];
            }
            static char unescapeChar(char c) {
                const char *p = escapeTable(true);
                for (;;) {
                    if (p[0] == '\0') return c;
                    if (p[0] == c) return p[1];
                    p += 2;
                }
            }
        private:
            static const char *escapeTable(bool excludeIdenticals) {
                return &"\"\"\\\\b\bf\fn\nr\rt\t"[excludeIdenticals ? 4 : 0];
            }
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        bool isNaN(T x) {
            return x != x;
        }
        template <typename T>
        bool isInfinity(T x) {
            return x != 0.0 && x * 2 == x;
        }
    }  // namespace Internals
}  // namespace ArduinoJson
#include <stdlib.h>  // for size_t
namespace ArduinoJson {
    namespace Internals {
        template <typename T, typename F>
        struct alias_cast_t {
            union {
                F raw;
                T data;
            };
        };
        template <typename T, typename F>
        T alias_cast(F raw_data) {
            alias_cast_t<T, F> ac;
            ac.raw = raw_data;
            return ac.data;
        }
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T, size_t = sizeof(T)>
        struct FloatTraits {};
        template <typename T>
        struct FloatTraits<T, 8 /*64bits*/> {
            typedef int64_t mantissa_type;
            static const short mantissa_bits = 52;
            static const mantissa_type mantissa_max =
                (static_cast<mantissa_type>(1) << mantissa_bits) - 1;
            typedef int16_t exponent_type;
            static const exponent_type exponent_max = 308;
            template <typename TExponent>
            static T make_float(T m, TExponent e) {
                if (e > 0) {
                    for (uint8_t index = 0; e != 0; index++) {
                        if (e & 1) m *= positiveBinaryPowerOfTen(index);
                        e >>= 1;
                    }
                }
                else {
                    e = TExponent(-e);
                    for (uint8_t index = 0; e != 0; index++) {
                        if (e & 1) m *= negativeBinaryPowerOfTen(index);
                        e >>= 1;
                    }
                }
                return m;
            }
            static T positiveBinaryPowerOfTen(int index) {
                static T factors[] = {
                    1e1,
                    1e2,
                    1e4,
                    1e8,
                    1e16,
                    forge(0x4693B8B5, 0xB5056E17),  // 1e32
                    forge(0x4D384F03, 0xE93FF9F5),  // 1e64
                    forge(0x5A827748, 0xF9301D32),  // 1e128
                    forge(0x75154FDD, 0x7F73BF3C)   // 1e256
                };
                return factors[index];
            }
            static T negativeBinaryPowerOfTen(int index) {
                static T factors[] = {
                    forge(0x3FB99999, 0x9999999A),  // 1e-1
                    forge(0x3F847AE1, 0x47AE147B),  // 1e-2
                    forge(0x3F1A36E2, 0xEB1C432D),  // 1e-4
                    forge(0x3E45798E, 0xE2308C3A),  // 1e-8
                    forge(0x3C9CD2B2, 0x97D889BC),  // 1e-16
                    forge(0x3949F623, 0xD5A8A733),  // 1e-32
                    forge(0x32A50FFD, 0x44F4A73D),  // 1e-64
                    forge(0x255BBA08, 0xCF8C979D),  // 1e-128
                    forge(0x0AC80628, 0x64AC6F43)   // 1e-256
                };
                return factors[index];
            }
            static T negativeBinaryPowerOfTenPlusOne(int index) {
                static T factors[] = {
                    1e0,
                    forge(0x3FB99999, 0x9999999A),  // 1e-1
                    forge(0x3F50624D, 0xD2F1A9FC),  // 1e-3
                    forge(0x3E7AD7F2, 0x9ABCAF48),  // 1e-7
                    forge(0x3CD203AF, 0x9EE75616),  // 1e-15
                    forge(0x398039D6, 0x65896880),  // 1e-31
                    forge(0x32DA53FC, 0x9631D10D),  // 1e-63
                    forge(0x25915445, 0x81B7DEC2),  // 1e-127
                    forge(0x0AFE07B2, 0x7DD78B14)   // 1e-255
                };
                return factors[index];
            }
            static T nan() {
                return forge(0x7ff80000, 0x00000000);
            }
            static T inf() {
                return forge(0x7ff00000, 0x00000000);
            }
            static T forge(uint32_t msb, uint32_t lsb) {
                return alias_cast<T>((uint64_t(msb) << 32) | lsb);
            }
        };
        template <typename T>
        struct FloatTraits<T, 4 /*32bits*/> {
            typedef int32_t mantissa_type;
            static const short mantissa_bits = 23;
            static const mantissa_type mantissa_max =
                (static_cast<mantissa_type>(1) << mantissa_bits) - 1;
            typedef int8_t exponent_type;
            static const exponent_type exponent_max = 38;
            template <typename TExponent>
            static T make_float(T m, TExponent e) {
                if (e > 0) {
                    for (uint8_t index = 0; e != 0; index++) {
                        if (e & 1) m *= positiveBinaryPowerOfTen(index);
                        e >>= 1;
                    }
                }
                else {
                    e = -e;
                    for (uint8_t index = 0; e != 0; index++) {
                        if (e & 1) m *= negativeBinaryPowerOfTen(index);
                        e >>= 1;
                    }
                }
                return m;
            }
            static T positiveBinaryPowerOfTen(int index) {
                static T factors[] = { 1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f };
                return factors[index];
            }
            static T negativeBinaryPowerOfTen(int index) {
                static T factors[] = { 1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f };
                return factors[index];
            }
            static T negativeBinaryPowerOfTenPlusOne(int index) {
                static T factors[] = { 1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f };
                return factors[index];
            }
            static T forge(uint32_t bits) {
                return alias_cast<T>(bits);
            }
            static T nan() {
                return forge(0x7fc00000);
            }
            static T inf() {
                return forge(0x7f800000);
            }
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename TFloat>
        struct FloatParts {
            uint32_t integral;
            uint32_t decimal;
            int16_t exponent;
            int8_t decimalPlaces;
            FloatParts(TFloat value) {
                uint32_t maxDecimalPart = sizeof(TFloat) >= 8 ? 1000000000 : 1000000;
                decimalPlaces = sizeof(TFloat) >= 8 ? 9 : 6;
                exponent = normalize(value);
                integral = uint32_t(value);
                for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) {
                    maxDecimalPart /= 10;
                    decimalPlaces--;
                }
                TFloat remainder = (value - TFloat(integral)) * TFloat(maxDecimalPart);
                decimal = uint32_t(remainder);
                remainder = remainder - TFloat(decimal);
                decimal += uint32_t(remainder * 2);
                if (decimal >= maxDecimalPart) {
                    decimal = 0;
                    integral++;
                    if (exponent && integral >= 10) {
                        exponent++;
                        integral = 1;
                    }
                }
                while (decimal % 10 == 0 && decimalPlaces > 0) {
                    decimal /= 10;
                    decimalPlaces--;
                }
            }
            static int16_t normalize(TFloat& value) {
                typedef FloatTraits<TFloat> traits;
                int16_t powersOf10 = 0;
                int8_t index = sizeof(TFloat) == 8 ? 8 : 5;
                int bit = 1 << index;
                if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) {
                    for (; index >= 0; index--) {
                        if (value >= traits::positiveBinaryPowerOfTen(index)) {
                            value *= traits::negativeBinaryPowerOfTen(index);
                            powersOf10 = int16_t(powersOf10 + bit);
                        }
                        bit >>= 1;
                    }
                }
                if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) {
                    for (; index >= 0; index--) {
                        if (value < traits::negativeBinaryPowerOfTenPlusOne(index)) {
                            value *= traits::positiveBinaryPowerOfTen(index);
                            powersOf10 = int16_t(powersOf10 - bit);
                        }
                        bit >>= 1;
                    }
                }
                return powersOf10;
            }
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename Print>
        class JsonWriter {
        public:
            explicit JsonWriter(Print &sink) : _sink(sink), _length(0) {}
            size_t bytesWritten() const {
                return _length;
            }
            void beginArray() {
                writeRaw('[');
            }
            void endArray() {
                writeRaw(']');
            }
            void beginObject() {
                writeRaw('{');
            }
            void endObject() {
                writeRaw('}');
            }
            void writeColon() {
                writeRaw(':');
            }
            void writeComma() {
                writeRaw(',');
            }
            void writeBoolean(bool value) {
                writeRaw(value ? "true" : "false");
            }
            void writeString(const char *value) {
                if (!value) {
                    writeRaw("null");
                }
                else {
                    writeRaw('\"');
                    while (*value) writeChar(*value++);
                    writeRaw('\"');
                }
            }
            void writeChar(char c) {
                char specialChar = Encoding::escapeChar(c);
                if (specialChar) {
                    writeRaw('\\');
                    writeRaw(specialChar);
                }
                else {
                    writeRaw(c);
                }
            }
            template <typename TFloat>
            void writeFloat(TFloat value) {
                if (isNaN(value)) return writeRaw("NaN");
                if (value < 0.0) {
                    writeRaw('-');
                    value = -value;
                }
                if (isInfinity(value)) return writeRaw("Infinity");
                FloatParts<TFloat> parts(value);
                writeInteger(parts.integral);
                if (parts.decimalPlaces) writeDecimals(parts.decimal, parts.decimalPlaces);
                if (parts.exponent < 0) {
                    writeRaw("e-");
                    writeInteger(-parts.exponent);
                }
                if (parts.exponent > 0) {
                    writeRaw('e');
                    writeInteger(parts.exponent);
                }
            }
            template <typename UInt>
            void writeInteger(UInt value) {
                char buffer[22];
                char *end = buffer + sizeof(buffer) - 1;
                char *ptr = end;
                *ptr = 0;
                do {
                    *--ptr = char(value % 10 + '0');
                    value = UInt(value / 10);
                } while (value);
                writeRaw(ptr);
            }
            void writeDecimals(uint32_t value, int8_t width) {
                char buffer[16];
                char *ptr = buffer + sizeof(buffer) - 1;
                *ptr = 0;
                while (width--) {
                    *--ptr = char(value % 10 + '0');
                    value /= 10;
                }
                *--ptr = '.';
                writeRaw(ptr);
            }
            void writeRaw(const char *s) {
                _length += _sink.print(s);
            }
            void writeRaw(char c) {
                _length += _sink.print(c);
            }
        protected:
            Print &_sink;
            size_t _length;
        private:
            JsonWriter &operator=(const JsonWriter &);  // cannot be assigned
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    class JsonArray;
    class JsonObject;
    class JsonVariant;
    namespace Internals {
        class JsonArraySubscript;
        template <typename TKey>
        class JsonObjectSubscript;
        template <typename Writer>
        class JsonSerializer {
        public:
            static void serialize(const JsonArray &, Writer &);
            static void serialize(const JsonArraySubscript &, Writer &);
            static void serialize(const JsonObject &, Writer &);
            template <typename TKey>
            static void serialize(const JsonObjectSubscript<TKey> &, Writer &);
            static void serialize(const JsonVariant &, Writer &);
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename Print>
        class Prettyfier {
        public:
            explicit Prettyfier(IndentedPrint<Print>& p) : _sink(p) {
                _previousChar = 0;
                _inString = false;
            }
            size_t print(char c) {
                size_t n = _inString ? handleStringChar(c) : handleMarkupChar(c);
                _previousChar = c;
                return n;
            }
            size_t print(const char* s) {
                size_t n = 0;
                while (*s) n += print(*s++);
                return n;
            }
        private:
            Prettyfier& operator=(const Prettyfier&);  // cannot be assigned
            bool inEmptyBlock() {
                return _previousChar == '{' || _previousChar == '[';
            }
            size_t handleStringChar(char c) {
                bool isQuote = c == '"' && _previousChar != '\\';
                if (isQuote) _inString = false;
                return _sink.print(c);
            }
            size_t handleMarkupChar(char c) {
                switch (c) {
                case '{':
                case '[':
                    return writeBlockOpen(c);
                case '}':
                case ']':
                    return writeBlockClose(c);
                case ':':
                    return writeColon();
                case ',':
                    return writeComma();
                case '"':
                    return writeQuoteOpen();
                default:
                    return writeNormalChar(c);
                }
            }
            size_t writeBlockClose(char c) {
                size_t n = 0;
                n += unindentIfNeeded();
                n += _sink.print(c);
                return n;
            }
            size_t writeBlockOpen(char c) {
                size_t n = 0;
                n += indentIfNeeded();
                n += _sink.print(c);
                return n;
            }
            size_t writeColon() {
                size_t n = 0;
                n += _sink.print(": ");
                return n;
            }
            size_t writeComma() {
                size_t n = 0;
                n += _sink.print(",\r\n");
                return n;
            }
            size_t writeQuoteOpen() {
                _inString = true;
                size_t n = 0;
                n += indentIfNeeded();
                n += _sink.print('"');
                return n;
            }
            size_t writeNormalChar(char c) {
                size_t n = 0;
                n += indentIfNeeded();
                n += _sink.print(c);
                return n;
            }
            size_t indentIfNeeded() {
                if (!inEmptyBlock()) return 0;
                _sink.indent();
                return _sink.print("\r\n");
            }
            size_t unindentIfNeeded() {
                if (inEmptyBlock()) return 0;
                _sink.unindent();
                return _sink.print("\r\n");
            }
            char _previousChar;
            IndentedPrint<Print>& _sink;
            bool _inString;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        class StaticStringBuilder {
        public:
            StaticStringBuilder(char *buf, size_t size) : end(buf + size - 1), p(buf) {
                *p = '\0';
            }
            size_t print(char c) {
                if (p >= end) return 0;
                *p++ = c;
                *p = '\0';
                return 1;
            }
            size_t print(const char *s) {
                char *begin = p;
                while (p < end && *s) *p++ = *s++;
                *p = '\0';
                return size_t(p - begin);
            }
        private:
            char *end;
            char *p;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
#if ARDUINOJSON_ENABLE_STD_STREAM
#if ARDUINOJSON_ENABLE_STD_STREAM
#include <ostream>
namespace ArduinoJson {
    namespace Internals {
        class StreamPrintAdapter {
        public:
            explicit StreamPrintAdapter(std::ostream& os) : _os(os) {}
            size_t print(char c) {
                _os << c;
                return 1;
            }
            size_t print(const char* s) {
                _os << s;
                return strlen(s);
            }
        private:
            StreamPrintAdapter& operator=(const StreamPrintAdapter&);
            std::ostream& _os;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
#endif  // ARDUINOJSON_ENABLE_STD_STREAM
#endif
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        class JsonPrintable {
        public:
            template <typename Print>
            typename EnableIf<!StringTraits<Print>::has_append, size_t>::type printTo(
                Print &print) const {
                JsonWriter<Print> writer(print);
                JsonSerializer<JsonWriter<Print> >::serialize(downcast(), writer);
                return writer.bytesWritten();
            }
#if ARDUINOJSON_ENABLE_STD_STREAM
            std::ostream &printTo(std::ostream &os) const {
                StreamPrintAdapter adapter(os);
                printTo(adapter);
                return os;
            }
#endif
            size_t printTo(char *buffer, size_t bufferSize) const {
                StaticStringBuilder sb(buffer, bufferSize);
                return printTo(sb);
            }
            template <size_t N>
            size_t printTo(char(&buffer)[N]) const {
                return printTo(buffer, N);
            }
            template <typename TString>
            typename EnableIf<StringTraits<TString>::has_append, size_t>::type printTo(
                TString &str) const {
                DynamicStringBuilder<TString> sb(str);
                return printTo(sb);
            }
            template <typename Print>
            size_t prettyPrintTo(IndentedPrint<Print> &print) const {
                Prettyfier<Print> p(print);
                return printTo(p);
            }
            size_t prettyPrintTo(char *buffer, size_t bufferSize) const {
                StaticStringBuilder sb(buffer, bufferSize);
                return prettyPrintTo(sb);
            }
            template <size_t N>
            size_t prettyPrintTo(char(&buffer)[N]) const {
                return prettyPrintTo(buffer, N);
            }
            template <typename Print>
            typename EnableIf<!StringTraits<Print>::has_append, size_t>::type
                prettyPrintTo(Print &print) const {
                IndentedPrint<Print> indentedPrint(print);
                return prettyPrintTo(indentedPrint);
            }
            template <typename TString>
            typename EnableIf<StringTraits<TString>::has_append, size_t>::type
                prettyPrintTo(TString &str) const {
                DynamicStringBuilder<TString> sb(str);
                return prettyPrintTo(sb);
            }
            size_t measureLength() const {
                DummyPrint dp;
                return printTo(dp);
            }
            size_t measurePrettyLength() const {
                DummyPrint dp;
                return prettyPrintTo(dp);
            }
        private:
            const T &downcast() const {
                return *static_cast<const T *>(this);
            }
        };
#if ARDUINOJSON_ENABLE_STD_STREAM
        template <typename T>
        inline std::ostream &operator<<(std::ostream &os, const JsonPrintable<T> &v) {
            return v.printTo(os);
        }
#endif
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename TImpl>
        class JsonVariantBase : public JsonPrintable<TImpl>,
            public JsonVariantCasts<TImpl>,
            public JsonVariantComparisons<TImpl>,
            public JsonVariantOr<TImpl>,
            public JsonVariantSubscripts<TImpl>,
            public JsonVariantTag {};
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        class RawJsonString {
        public:
            explicit RawJsonString(T str) : _str(str) {}
            operator T() const {
                return _str;
            }
        private:
            T _str;
        };
        template <typename String>
        struct StringTraits<RawJsonString<String>, void> {
            static bool is_null(RawJsonString<String> source) {
                return StringTraits<String>::is_null(static_cast<String>(source));
            }
            typedef RawJsonString<const char*> duplicate_t;
            template <typename Buffer>
            static duplicate_t duplicate(RawJsonString<String> source, Buffer* buffer) {
                return duplicate_t(StringTraits<String>::duplicate(source, buffer));
            }
            static const bool has_append = false;
            static const bool has_equals = false;
            static const bool should_duplicate = StringTraits<String>::should_duplicate;
        };
    }  // namespace Internals
    template <typename T>
    inline Internals::RawJsonString<T> RawJson(T str) {
        return Internals::RawJsonString<T>(str);
    }
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        struct IsFloatingPoint {
            static const bool value = IsSame<T, float>::value || IsSame<T, double>::value;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        struct RemoveConst {
            typedef T type;
        };
        template <typename T>
        struct RemoveConst<const T> {
            typedef T type;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    class JsonArray;
    class JsonObject;
    class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
        template <typename Print>
        friend class Internals::JsonSerializer;
    public:
        JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
        JsonVariant(bool value) {
            using namespace Internals;
            _type = JSON_BOOLEAN;
            _content.asInteger = static_cast<JsonUInt>(value);
        }
        template <typename T>
        JsonVariant(T value, typename Internals::EnableIf<
            Internals::IsFloatingPoint<T>::value>::type * = 0) {
            using namespace Internals;
            _type = JSON_FLOAT;
            _content.asFloat = static_cast<JsonFloat>(value);
        }
        template <typename T>
        DEPRECATED("Second argument is not supported anymore")
            JsonVariant(T value, uint8_t,
                typename Internals::EnableIf<
                Internals::IsFloatingPoint<T>::value>::type * = 0) {
            using namespace Internals;
            _type = JSON_FLOAT;
            _content.asFloat = static_cast<JsonFloat>(value);
        }
        template <typename T>
        JsonVariant(
            T value,
            typename Internals::EnableIf<Internals::IsSignedIntegral<T>::value ||
            Internals::IsSame<T, char>::value>::type * =
            0) {
            using namespace Internals;
            if (value >= 0) {
                _type = JSON_POSITIVE_INTEGER;
                _content.asInteger = static_cast<JsonUInt>(value);
            }
            else {
                _type = JSON_NEGATIVE_INTEGER;
                _content.asInteger = static_cast<JsonUInt>(-value);
            }
        }
        template <typename T>
        JsonVariant(T value,
            typename Internals::EnableIf<
            Internals::IsUnsignedIntegral<T>::value>::type * = 0) {
            using namespace Internals;
            _type = JSON_POSITIVE_INTEGER;
            _content.asInteger = static_cast<JsonUInt>(value);
        }
        template <typename TChar>
        JsonVariant(
            const TChar *value,
            typename Internals::EnableIf<Internals::IsChar<TChar>::value>::type * =
            0) {
            _type = Internals::JSON_STRING;
            _content.asString = reinterpret_cast<const char *>(value);
        }
        JsonVariant(Internals::RawJsonString<const char *> value) {
            _type = Internals::JSON_UNPARSED;
            _content.asString = value;
        }
        JsonVariant(const JsonArray &array);
        JsonVariant(const JsonObject &object);
        template <typename T>
        const typename Internals::EnableIf<Internals::IsIntegral<T>::value, T>::type
            as() const {
            return variantAsInteger<T>();
        }
        template <typename T>
        const typename Internals::EnableIf<Internals::IsSame<T, bool>::value, T>::type
            as() const {
            return variantAsInteger<int>() != 0;
        }
        template <typename T>
        const typename Internals::EnableIf<Internals::IsFloatingPoint<T>::value,
            T>::type
            as() const {
            return variantAsFloat<T>();
        }
        template <typename T>
        typename Internals::EnableIf<Internals::IsSame<T, const char *>::value ||
            Internals::IsSame<T, char *>::value,
            const char *>::type
            as() const {
            return variantAsString();
        }
        template <typename T>
        typename Internals::EnableIf<Internals::StringTraits<T>::has_append, T>::type
            as() const {
            const char *cstr = variantAsString();
            if (cstr) return T(cstr);
            T s;
            printTo(s);
            return s;
        }
        template <typename T>
        typename Internals::EnableIf<
            Internals::IsSame<typename Internals::RemoveReference<T>::type,
            JsonArray>::value,
            JsonArray &>::type
            as() const {
            return variantAsArray();
        }
        template <typename T>
        typename Internals::EnableIf<
            Internals::IsSame<typename Internals::RemoveReference<T>::type,
            const JsonArray>::value,
            const JsonArray &>::type
            as() const {
            return variantAsArray();
        }
        template <typename T>
        typename Internals::EnableIf<
            Internals::IsSame<typename Internals::RemoveReference<T>::type,
            JsonObject>::value,
            JsonObject &>::type
            as() const {
            return variantAsObject();
        }
        template <typename T>
        typename Internals::EnableIf<
            Internals::IsSame<typename Internals::RemoveReference<T>::type,
            const JsonObject>::value,
            const JsonObject &>::type
            as() const {
            return variantAsObject();
        }
        template <typename T>
        typename Internals::EnableIf<Internals::IsSame<T, JsonVariant>::value,
            T>::type
            as() const {
            return *this;
        }
        template <typename T>
        typename Internals::EnableIf<Internals::IsIntegral<T>::value, bool>::type is()
            const {
            return variantIsInteger();
        }
        template <typename T>
        typename Internals::EnableIf<Internals::IsFloatingPoint<T>::value, bool>::type
            is() const {
            return variantIsFloat();
        }
        template <typename T>
        typename Internals::EnableIf<Internals::IsSame<T, bool>::value, bool>::type
            is() const {
            return variantIsBoolean();
        }
        template <typename T>
        typename Internals::EnableIf<Internals::IsSame<T, const char *>::value ||
            Internals::IsSame<T, char *>::value ||
            Internals::StringTraits<T>::has_append,
            bool>::type
            is() const {
            return variantIsString();
        }
        template <typename T>
        typename Internals::EnableIf<
            Internals::IsSame<typename Internals::RemoveConst<
            typename Internals::RemoveReference<T>::type>::type,
            JsonArray>::value,
            bool>::type
            is() const {
            return variantIsArray();
        }
        template <typename T>
        typename Internals::EnableIf<
            Internals::IsSame<typename Internals::RemoveConst<
            typename Internals::RemoveReference<T>::type>::type,
            JsonObject>::value,
            bool>::type
            is() const {
            return variantIsObject();
        }
        bool success() const {
            return _type != Internals::JSON_UNDEFINED;
        }
    private:
        JsonArray &variantAsArray() const;
        JsonObject &variantAsObject() const;
        const char *variantAsString() const;
        template <typename T>
        T variantAsFloat() const;
        template <typename T>
        T variantAsInteger() const;
        bool variantIsBoolean() const;
        bool variantIsFloat() const;
        bool variantIsInteger() const;
        bool variantIsArray() const {
            return _type == Internals::JSON_ARRAY;
        }
        bool variantIsObject() const {
            return _type == Internals::JSON_OBJECT;
        }
        bool variantIsString() const {
            return _type == Internals::JSON_STRING ||
                (_type == Internals::JSON_UNPARSED && _content.asString &&
                    !strcmp("null", _content.asString));
        }
        Internals::JsonVariantType _type;
        Internals::JsonVariantContent _content;
    };
    DEPRECATED("Decimal places are ignored, use the float value instead")
        inline JsonVariant float_with_n_digits(float value, uint8_t) {
        return JsonVariant(value);
    }
    DEPRECATED("Decimal places are ignored, use the double value instead")
        inline JsonVariant double_with_n_digits(double value, uint8_t) {
        return JsonVariant(value);
    }
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        struct IsArray {
            static const bool value = false;
        };
        template <typename T>
        struct IsArray<T[]> {
            static const bool value = true;
        };
        template <typename T, size_t N>
        struct IsArray<T[N]> {
            static const bool value = true;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    class JsonArray;
    class JsonObject;
    class JsonBuffer : Internals::NonCopyable {
    public:
        JsonArray &createArray();
        JsonObject &createObject();
        template <typename TString>
        DEPRECATED("char* are duplicated, you don't need strdup() anymore")
            typename Internals::EnableIf<!Internals::IsArray<TString>::value,
            const char *>::type strdup(const TString &src) {
            return Internals::StringTraits<TString>::duplicate(src, this);
        }
        template <typename TString>
        DEPRECATED("char* are duplicated, you don't need strdup() anymore")
            const char *strdup(TString *src) {
            return Internals::StringTraits<TString *>::duplicate(src, this);
        }
        virtual void *alloc(size_t size) = 0;
    protected:
        ~JsonBuffer() {}
        static FORCE_INLINE size_t round_size_up(size_t bytes) {
#if ARDUINOJSON_ENABLE_ALIGNMENT
            const size_t x = sizeof(void *) - 1;
            return (bytes + x) & ~x;
#else
            return bytes;
#endif
        }
    };
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename TChar>
        class StringWriter {
        public:
            class String {
            public:
                String(TChar** ptr) : _writePtr(ptr), _startPtr(*ptr) {}
                void append(char c) {
                    *(*_writePtr)++ = TChar(c);
                }
                const char* c_str() const {
                    *(*_writePtr)++ = 0;
                    return reinterpret_cast<const char*>(_startPtr);
                }
            private:
                TChar** _writePtr;
                TChar* _startPtr;
            };
            StringWriter(TChar* buffer) : _ptr(buffer) {}
            String startString() {
                return String(&_ptr);
            }
        private:
            TChar* _ptr;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename TReader, typename TWriter>
        class JsonParser {
        public:
            JsonParser(JsonBuffer *buffer, TReader reader, TWriter writer,
                uint8_t nestingLimit)
                : _buffer(buffer),
                _reader(reader),
                _writer(writer),
                _nestingLimit(nestingLimit) {}
            JsonArray &parseArray();
            JsonObject &parseObject();
            JsonVariant parseVariant() {
                JsonVariant result;
                parseAnythingTo(&result);
                return result;
            }
        private:
            JsonParser &operator=(const JsonParser &);  // non-copiable
            static bool eat(TReader &, char charToSkip);
            FORCE_INLINE bool eat(char charToSkip) {
                return eat(_reader, charToSkip);
            }
            const char *parseString();
            bool parseAnythingTo(JsonVariant *destination);
            inline bool parseArrayTo(JsonVariant *destination);
            inline bool parseObjectTo(JsonVariant *destination);
            inline bool parseStringTo(JsonVariant *destination);
            static inline bool isBetween(char c, char min, char max) {
                return min <= c && c <= max;
            }
            static inline bool canBeInNonQuotedString(char c) {
                return isBetween(c, '0', '9') || isBetween(c, '_', 'z') ||
                    isBetween(c, 'A', 'Z') || c == '+' || c == '-' || c == '.';
            }
            static inline bool isQuote(char c) {
                return c == '\'' || c == '\"';
            }
            JsonBuffer *_buffer;
            TReader _reader;
            TWriter _writer;
            uint8_t _nestingLimit;
        };
        template <typename TJsonBuffer, typename TString, typename Enable = void>
        struct JsonParserBuilder {
            typedef typename StringTraits<TString>::Reader InputReader;
            typedef JsonParser<InputReader, TJsonBuffer &> TParser;
            static TParser makeParser(TJsonBuffer *buffer, TString &json,
                uint8_t nestingLimit) {
                return TParser(buffer, InputReader(json), *buffer, nestingLimit);
            }
        };
        template <typename TJsonBuffer, typename TChar>
        struct JsonParserBuilder<TJsonBuffer, TChar *,
            typename EnableIf<!IsConst<TChar>::value>::type> {
            typedef typename StringTraits<TChar *>::Reader TReader;
            typedef StringWriter<TChar> TWriter;
            typedef JsonParser<TReader, TWriter> TParser;
            static TParser makeParser(TJsonBuffer *buffer, TChar *json,
                uint8_t nestingLimit) {
                return TParser(buffer, TReader(json), TWriter(json), nestingLimit);
            }
        };
        template <typename TJsonBuffer, typename TString>
        inline typename JsonParserBuilder<TJsonBuffer, TString>::TParser makeParser(
            TJsonBuffer *buffer, TString &json, uint8_t nestingLimit) {
            return JsonParserBuilder<TJsonBuffer, TString>::makeParser(buffer, json,
                nestingLimit);
        }
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename TDerived>
        class JsonBufferBase : public JsonBuffer {
        public:
            template <typename TString>
            typename Internals::EnableIf<!Internals::IsArray<TString>::value,
                JsonArray &>::type
                parseArray(const TString &json,
                    uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
                return Internals::makeParser(that(), json, nestingLimit).parseArray();
            }
            template <typename TString>
            JsonArray &parseArray(
                TString *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
                return Internals::makeParser(that(), json, nestingLimit).parseArray();
            }
            template <typename TString>
            JsonArray &parseArray(
                TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
                return Internals::makeParser(that(), json, nestingLimit).parseArray();
            }
            template <typename TString>
            typename Internals::EnableIf<!Internals::IsArray<TString>::value,
                JsonObject &>::type
                parseObject(const TString &json,
                    uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
                return Internals::makeParser(that(), json, nestingLimit).parseObject();
            }
            template <typename TString>
            JsonObject &parseObject(
                TString *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
                return Internals::makeParser(that(), json, nestingLimit).parseObject();
            }
            template <typename TString>
            JsonObject &parseObject(
                TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
                return Internals::makeParser(that(), json, nestingLimit).parseObject();
            }
            template <typename TString>
            typename Internals::EnableIf<!Internals::IsArray<TString>::value,
                JsonVariant>::type
                parse(const TString &json,
                    uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
                return Internals::makeParser(that(), json, nestingLimit).parseVariant();
            }
            template <typename TString>
            JsonVariant parse(TString *json,
                uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
                return Internals::makeParser(that(), json, nestingLimit).parseVariant();
            }
            template <typename TString>
            JsonVariant parse(TString &json,
                uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
                return Internals::makeParser(that(), json, nestingLimit).parseVariant();
            }
        protected:
            ~JsonBufferBase() {}
        private:
            TDerived *that() {
                return static_cast<TDerived *>(this);
            }
        };
    }  // namespace Internals
}  // namespace ArduinoJson
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
#elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic push
#endif
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#endif
namespace ArduinoJson {
    namespace Internals {
        class DefaultAllocator {
        public:
            void* allocate(size_t size) {
                return malloc(size);
            }
            void deallocate(void* pointer) {
                free(pointer);
            }
        };
        template <typename TAllocator>
        class DynamicJsonBufferBase
            : public JsonBufferBase<DynamicJsonBufferBase<TAllocator> > {
            struct Block;
            struct EmptyBlock {
                Block* next;
                size_t capacity;
                size_t size;
            };
            struct Block : EmptyBlock {
                uint8_t data[1];
            };
        public:
            enum { EmptyBlockSize = sizeof(EmptyBlock) };
            DynamicJsonBufferBase(size_t initialSize = 256)
                : _head(NULL), _nextBlockCapacity(initialSize) {}
            ~DynamicJsonBufferBase() {
                clear();
            }
            size_t size() const {
                size_t total = 0;
                for (const Block* b = _head; b; b = b->next) total += b->size;
                return total;
            }
            virtual void* alloc(size_t bytes) {
                alignNextAlloc();
                return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
            }
            void clear() {
                Block* currentBlock = _head;
                while (currentBlock != NULL) {
                    _nextBlockCapacity = currentBlock->capacity;
                    Block* nextBlock = currentBlock->next;
                    _allocator.deallocate(currentBlock);
                    currentBlock = nextBlock;
                }
                _head = 0;
            }
            class String {
            public:
                String(DynamicJsonBufferBase* parent)
                    : _parent(parent), _start(NULL), _length(0) {}
                void append(char c) {
                    if (_parent->canAllocInHead(1)) {
                        char* end = static_cast<char*>(_parent->allocInHead(1));
                        *end = c;
                        if (_length == 0) _start = end;
                    }
                    else {
                        char* newStart =
                            static_cast<char*>(_parent->allocInNewBlock(_length + 1));
                        if (_start && newStart) memcpy(newStart, _start, _length);
                        if (newStart) newStart[_length] = c;
                        _start = newStart;
                    }
                    _length++;
                }
                const char* c_str() {
                    append(0);
                    return _start;
                }
            private:
                DynamicJsonBufferBase* _parent;
                char* _start;
                size_t _length;
            };
            String startString() {
                return String(this);
            }
        private:
            void alignNextAlloc() {
                if (_head) _head->size = this->round_size_up(_head->size);
            }
            bool canAllocInHead(size_t bytes) const {
                return _head != NULL && _head->size + bytes <= _head->capacity;
            }
            void* allocInHead(size_t bytes) {
                void* p = _head->data + _head->size;
                _head->size += bytes;
                return p;
            }
            void* allocInNewBlock(size_t bytes) {
                size_t capacity = _nextBlockCapacity;
                if (bytes > capacity) capacity = bytes;
                if (!addNewBlock(capacity)) return NULL;
                _nextBlockCapacity *= 2;
                return allocInHead(bytes);
            }
            bool addNewBlock(size_t capacity) {
                size_t bytes = EmptyBlockSize + capacity;
                Block* block = static_cast<Block*>(_allocator.allocate(bytes));
                if (block == NULL) return false;
                block->capacity = capacity;
                block->size = 0;
                block->next = _head;
                _head = block;
                return true;
            }
            TAllocator _allocator;
            Block* _head;
            size_t _nextBlockCapacity;
        };
    }  // namespace Internals
#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic pop
#endif
#endif
    typedef Internals::DynamicJsonBufferBase<Internals::DefaultAllocator>
        DynamicJsonBuffer;
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        class JsonBufferAllocated {
        public:
            void *operator new(size_t n, JsonBuffer *jsonBuffer) throw() {
                if (!jsonBuffer) return NULL;
                return jsonBuffer->alloc(n);
            }
            void operator delete(void *, JsonBuffer *)throw();
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        struct ListNode : public Internals::JsonBufferAllocated {
            ListNode() throw() : next(NULL) {}
            ListNode<T> *next;
            T content;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        class ListConstIterator {
        public:
            explicit ListConstIterator(const ListNode<T> *node = NULL) : _node(node) {}
            const T &operator*() const {
                return _node->content;
            }
            const T *operator->() {
                return &_node->content;
            }
            bool operator==(const ListConstIterator<T> &other) const {
                return _node == other._node;
            }
            bool operator!=(const ListConstIterator<T> &other) const {
                return _node != other._node;
            }
            ListConstIterator<T> &operator++() {
                if (_node) _node = _node->next;
                return *this;
            }
            ListConstIterator<T> &operator+=(size_t distance) {
                while (_node && distance) {
                    _node = _node->next;
                    --distance;
                }
                return *this;
            }
        private:
            const ListNode<T> *_node;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        class List;
        template <typename T>
        class ListIterator {
            friend class List<T>;
        public:
            explicit ListIterator(ListNode<T> *node = NULL) : _node(node) {}
            T &operator*() const {
                return _node->content;
            }
            T *operator->() {
                return &_node->content;
            }
            bool operator==(const ListIterator<T> &other) const {
                return _node == other._node;
            }
            bool operator!=(const ListIterator<T> &other) const {
                return _node != other._node;
            }
            ListIterator<T> &operator++() {
                if (_node) _node = _node->next;
                return *this;
            }
            ListIterator<T> &operator+=(size_t distance) {
                while (_node && distance) {
                    _node = _node->next;
                    --distance;
                }
                return *this;
            }
            operator ListConstIterator<T>() const {
                return ListConstIterator<T>(_node);
            }
        private:
            ListNode<T> *_node;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        class List {
        public:
            typedef T value_type;
            typedef ListNode<T> node_type;
            typedef ListIterator<T> iterator;
            typedef ListConstIterator<T> const_iterator;
            explicit List(JsonBuffer *buffer) : _buffer(buffer), _firstNode(NULL) {}
            bool success() const {
                return _buffer != NULL;
            }
            size_t size() const {
                size_t nodeCount = 0;
                for (node_type *node = _firstNode; node; node = node->next) nodeCount++;
                return nodeCount;
            }
            iterator add() {
                node_type *newNode = new (_buffer) node_type();
                if (_firstNode) {
                    node_type *lastNode = _firstNode;
                    while (lastNode->next) lastNode = lastNode->next;
                    lastNode->next = newNode;
                }
                else {
                    _firstNode = newNode;
                }
                return iterator(newNode);
            }
            iterator begin() {
                return iterator(_firstNode);
            }
            iterator end() {
                return iterator(NULL);
            }
            const_iterator begin() const {
                return const_iterator(_firstNode);
            }
            const_iterator end() const {
                return const_iterator(NULL);
            }
            void remove(iterator it) {
                node_type *nodeToRemove = it._node;
                if (!nodeToRemove) return;
                if (nodeToRemove == _firstNode) {
                    _firstNode = nodeToRemove->next;
                }
                else {
                    for (node_type *node = _firstNode; node; node = node->next)
                        if (node->next == nodeToRemove) node->next = nodeToRemove->next;
                }
            }
        protected:
            JsonBuffer *_buffer;
        private:
            node_type *_firstNode;
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        class ReferenceType {
        public:
            bool operator==(const ReferenceType& other) const {
                return this == &other;
            }
            bool operator!=(const ReferenceType& other) const {
                return this != &other;
            }
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename Source, typename Enable = void>
        struct ValueSaver {
            template <typename Destination>
            static bool save(JsonBuffer*, Destination& destination, Source source) {
                destination = source;
                return true;
            }
        };
        template <typename Source>
        struct ValueSaver<
            Source, typename EnableIf<StringTraits<Source>::should_duplicate>::type> {
            template <typename Destination>
            static bool save(JsonBuffer* buffer, Destination& dest, Source source) {
                if (!StringTraits<Source>::is_null(source)) {
                    typename StringTraits<Source>::duplicate_t dup =
                        StringTraits<Source>::duplicate(source, buffer);
                    if (!dup) return false;
                    dest = dup;
                }
                else {
                    dest = reinterpret_cast<const char*>(0);
                }
                return true;
            }
        };
        template <typename Char>
        struct ValueSaver<
            Char*, typename EnableIf<!StringTraits<Char*>::should_duplicate>::type> {
            template <typename Destination>
            static bool save(JsonBuffer*, Destination& dest, Char* source) {
                dest = reinterpret_cast<const char*>(source);
                return true;
            }
        };
    }  // namespace Internals
}  // namespace ArduinoJson
#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \
  (sizeof(JsonArray) + (NUMBER_OF_ELEMENTS) * sizeof(JsonArray::node_type))
namespace ArduinoJson {
    class JsonObject;
    class JsonBuffer;
    namespace Internals {
        class JsonArraySubscript;
    }
    class JsonArray : public Internals::JsonPrintable<JsonArray>,
        public Internals::ReferenceType,
        public Internals::NonCopyable,
        public Internals::List<JsonVariant>,
        public Internals::JsonBufferAllocated {
    public:
        explicit JsonArray(JsonBuffer *buffer) throw()
            : Internals::List<JsonVariant>(buffer) {}
        const Internals::JsonArraySubscript operator[](size_t index) const;
        Internals::JsonArraySubscript operator[](size_t index);
        template <typename T>
        bool add(const T &value) {
            return add_impl<const T &>(value);
        }
        template <typename T>
        bool add(T *value) {
            return add_impl<T *>(value);
        }
        template <typename T>
        DEPRECATED("Second argument is not supported anymore")
            bool add(T value, uint8_t) {
            return add_impl<const JsonVariant &>(JsonVariant(value));
        }
        template <typename T>
        bool set(size_t index, const T &value) {
            return set_impl<const T &>(index, value);
        }
        template <typename T>
        bool set(size_t index, T *value) {
            return set_impl<T *>(index, value);
        }
        template <typename T>
        typename Internals::EnableIf<Internals::IsFloatingPoint<T>::value, bool>::type
            set(size_t index, T value, uint8_t decimals) {
            return set_impl<const JsonVariant &>(index, JsonVariant(value, decimals));
        }
        template <typename T>
        typename Internals::JsonVariantAs<T>::type get(size_t index) const {
            const_iterator it = begin() += index;
            return it != end() ? it->as<T>() : Internals::JsonVariantDefault<T>::get();
        }
        template <typename T>
        bool is(size_t index) const {
            const_iterator it = begin() += index;
            return it != end() ? it->is<T>() : false;
        }
        JsonArray &createNestedArray();
        JsonObject &createNestedObject();
        void remove(size_t index) {
            remove(begin() += index);
        }
        using Internals::List<JsonVariant>::remove;
        static JsonArray &invalid() {
            static JsonArray instance(NULL);
            return instance;
        }
        template <typename T, size_t N>
        bool copyFrom(T(&array)[N]) {
            return copyFrom(array, N);
        }
        template <typename T>
        bool copyFrom(T *array, size_t len) {
            bool ok = true;
            for (size_t i = 0; i < len; i++) {
                ok &= add(array[i]);
            }
            return ok;
        }
        template <typename T, size_t N1, size_t N2>
        bool copyFrom(T(&array)[N1][N2]) {
            bool ok = true;
            for (size_t i = 0; i < N1; i++) {
                JsonArray &nestedArray = createNestedArray();
                for (size_t j = 0; j < N2; j++) {
                    ok &= nestedArray.add(array[i][j]);
                }
            }
            return ok;
        }
        template <typename T, size_t N>
        size_t copyTo(T(&array)[N]) const {
            return copyTo(array, N);
        }
        template <typename T>
        size_t copyTo(T *array, size_t len) const {
            size_t i = 0;
            for (const_iterator it = begin(); it != end() && i < len; ++it)
                array[i++] = *it;
            return i;
        }
        template <typename T, size_t N1, size_t N2>
        void copyTo(T(&array)[N1][N2]) const {
            size_t i = 0;
            for (const_iterator it = begin(); it != end() && i < N1; ++it) {
                it->as<JsonArray>().copyTo(array[i++]);
            }
        }
#if ARDUINOJSON_ENABLE_DEPRECATED
        DEPRECATED("use remove() instead")
            FORCE_INLINE void removeAt(size_t index) {
            return remove(index);
        }
#endif
    private:
        template <typename TValueRef>
        bool set_impl(size_t index, TValueRef value) {
            iterator it = begin() += index;
            if (it == end()) return false;
            return Internals::ValueSaver<TValueRef>::save(_buffer, *it, value);
        }
        template <typename TValueRef>
        bool add_impl(TValueRef value) {
            iterator it = Internals::List<JsonVariant>::add();
            if (it == end()) return false;
            return Internals::ValueSaver<TValueRef>::save(_buffer, *it, value);
        }
    };
    namespace Internals {
        template <>
        struct JsonVariantDefault<JsonArray> {
            static JsonArray &get() {
                return JsonArray::invalid();
            }
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    struct JsonPair {
        const char* key;
        JsonVariant value;
    };
}  // namespace ArduinoJson
#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \
  (sizeof(JsonObject) + (NUMBER_OF_ELEMENTS) * sizeof(JsonObject::node_type))
namespace ArduinoJson {
    class JsonArray;
    class JsonBuffer;
    namespace Internals {
        template <typename>
        class JsonObjectSubscript;
    }
    class JsonObject : public Internals::JsonPrintable<JsonObject>,
        public Internals::ReferenceType,
        public Internals::NonCopyable,
        public Internals::List<JsonPair>,
        public Internals::JsonBufferAllocated {
    public:
        explicit JsonObject(JsonBuffer* buffer) throw()
            : Internals::List<JsonPair>(buffer) {}
        template <typename TString>
        Internals::JsonObjectSubscript<const TString&> operator[](
            const TString& key) {
            return Internals::JsonObjectSubscript<const TString&>(*this, key);
        }
        template <typename TString>
        Internals::JsonObjectSubscript<TString*> operator[](TString* key) {
            return Internals::JsonObjectSubscript<TString*>(*this, key);
        }
        template <typename TString>
        const Internals::JsonObjectSubscript<const TString&> operator[](
            const TString& key) const {
            return Internals::JsonObjectSubscript<const TString&>(
                *const_cast<JsonObject*>(this), key);
        }
        template <typename TString>
        const Internals::JsonObjectSubscript<TString*> operator[](
            TString* key) const {
            return Internals::JsonObjectSubscript<TString*>(
                *const_cast<JsonObject*>(this), key);
        }
        template <typename TValue, typename TString>
        bool set(const TString& key, const TValue& value) {
            return set_impl<const TString&, const TValue&>(key, value);
        }
        template <typename TValue, typename TString>
        bool set(const TString& key, TValue* value) {
            return set_impl<const TString&, TValue*>(key, value);
        }
        template <typename TValue, typename TString>
        bool set(TString* key, const TValue& value) {
            return set_impl<TString*, const TValue&>(key, value);
        }
        template <typename TValue, typename TString>
        bool set(TString* key, TValue* value) {
            return set_impl<TString*, TValue*>(key, value);
        }
        template <typename TValue, typename TString>
        DEPRECATED("Second argument is not supported anymore")
            typename Internals::EnableIf<Internals::IsFloatingPoint<TValue>::value,
            bool>::type
            set(const TString& key, TValue value, uint8_t) {
            return set_impl<const TString&, const JsonVariant&>(key,
                JsonVariant(value));
        }
        template <typename TValue, typename TString>
        DEPRECATED("Second argument is not supported anymore")
            typename Internals::EnableIf<Internals::IsFloatingPoint<TValue>::value,
            bool>::type
            set(TString* key, TValue value, uint8_t) {
            return set_impl<TString*, const JsonVariant&>(key, JsonVariant(value));
        }
        template <typename TValue, typename TString>
        typename Internals::JsonVariantAs<TValue>::type get(
            const TString& key) const {
            return get_impl<const TString&, TValue>(key);
        }
        template <typename TValue, typename TString>
        typename Internals::JsonVariantAs<TValue>::type get(TString* key) const {
            return get_impl<TString*, TValue>(key);
        }
        template <typename TValue, typename TString>
        bool is(const TString& key) const {
            return is_impl<const TString&, TValue>(key);
        }
        template <typename TValue, typename TString>
        bool is(TString* key) const {
            return is_impl<TString*, TValue>(key);
        }
        template <typename TString>
        JsonArray& createNestedArray(const TString& key) {
            return createNestedArray_impl<const TString&>(key);
        }
        template <typename TString>
        JsonArray& createNestedArray(TString* key) {
            return createNestedArray_impl<TString*>(key);
        }
        template <typename TString>
        JsonObject& createNestedObject(const TString& key) {
            return createNestedObject_impl<const TString&>(key);
        }
        template <typename TString>
        JsonObject& createNestedObject(TString* key) {
            return createNestedObject_impl<TString*>(key);
        }
        template <typename TString>
        bool containsKey(const TString& key) const {
            return findKey<const TString&>(key) != end();
        }
        template <typename TString>
        bool containsKey(TString* key) const {
            return findKey<TString*>(key) != end();
        }
        template <typename TString>
        void remove(const TString& key) {
            remove(findKey<const TString&>(key));
        }
        template <typename TString>
        void remove(TString* key) {
            remove(findKey<TString*>(key));
        }
        using Internals::List<JsonPair>::remove;
        static JsonObject& invalid() {
            static JsonObject instance(NULL);
            return instance;
        }
    private:
        template <typename TStringRef>
        iterator findKey(TStringRef key) {
            iterator it;
            for (it = begin(); it != end(); ++it) {
                if (Internals::StringTraits<TStringRef>::equals(key, it->key)) break;
            }
            return it;
        }
        template <typename TStringRef>
        const_iterator findKey(TStringRef key) const {
            return const_cast<JsonObject*>(this)->findKey<TStringRef>(key);
        }
        template <typename TStringRef, typename TValue>
        typename Internals::JsonVariantAs<TValue>::type get_impl(
            TStringRef key) const {
            const_iterator it = findKey<TStringRef>(key);
            return it != end() ? it->value.as<TValue>()
                : Internals::JsonVariantDefault<TValue>::get();
        }
        template <typename TStringRef, typename TValueRef>
        bool set_impl(TStringRef key, TValueRef value) {
            if (Internals::StringTraits<TStringRef>::is_null(key)) return false;
            iterator it = findKey<TStringRef>(key);
            if (it == end()) {
                it = Internals::List<JsonPair>::add();
                if (it == end()) return false;
                bool key_ok =
                    Internals::ValueSaver<TStringRef>::save(_buffer, it->key, key);
                if (!key_ok) return false;
            }
            return Internals::ValueSaver<TValueRef>::save(_buffer, it->value, value);
        }
        template <typename TStringRef, typename TValue>
        bool is_impl(TStringRef key) const {
            const_iterator it = findKey<TStringRef>(key);
            return it != end() ? it->value.is<TValue>() : false;
        }
        template <typename TStringRef>
        JsonArray& createNestedArray_impl(TStringRef key);
        template <typename TStringRef>
        JsonObject& createNestedObject_impl(TStringRef key);
    };
    namespace Internals {
        template <>
        struct JsonVariantDefault<JsonObject> {
            static JsonObject& get() {
                return JsonObject::invalid();
            }
        };
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        class StaticJsonBufferBase : public JsonBufferBase<StaticJsonBufferBase> {
        public:
            class String {
            public:
                String(StaticJsonBufferBase* parent) : _parent(parent) {
                    _start = parent->_buffer + parent->_size;
                }
                void append(char c) {
                    if (_parent->canAlloc(1)) {
                        char* last = static_cast<char*>(_parent->doAlloc(1));
                        *last = c;
                    }
                }
                const char* c_str() const {
                    if (_parent->canAlloc(1)) {
                        char* last = static_cast<char*>(_parent->doAlloc(1));
                        *last = '\0';
                        return _start;
                    }
                    else {
                        return NULL;
                    }
                }
            private:
                StaticJsonBufferBase* _parent;
                char* _start;
            };
            StaticJsonBufferBase(char* buffer, size_t capa)
                : _buffer(buffer), _capacity(capa), _size(0) {}
            size_t capacity() const {
                return _capacity;
            }
            size_t size() const {
                return _size;
            }
            virtual void* alloc(size_t bytes) {
                alignNextAlloc();
                if (!canAlloc(bytes)) return NULL;
                return doAlloc(bytes);
            }
            void clear() {
                _size = 0;
            }
            String startString() {
                return String(this);
            }
        protected:
            ~StaticJsonBufferBase() {}
        private:
            void alignNextAlloc() {
                _size = round_size_up(_size);
            }
            bool canAlloc(size_t bytes) const {
                return _size + bytes <= _capacity;
            }
            void* doAlloc(size_t bytes) {
                void* p = &_buffer[_size];
                _size += bytes;
                return p;
            }
            char* _buffer;
            size_t _capacity;
            size_t _size;
        };
    }  // namespace Internals
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
#elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic push
#endif
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#endif
    template <size_t CAPACITY>
    class StaticJsonBuffer : public Internals::StaticJsonBufferBase {
    public:
        explicit StaticJsonBuffer()
            : Internals::StaticJsonBufferBase(_buffer, CAPACITY) {}
    private:
        char _buffer[CAPACITY];
    };
}  // namespace ArduinoJson
#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic pop
#endif
#endif
namespace ArduinoJson {
    namespace Internals {
        template <typename TInput>
        void skipSpacesAndComments(TInput& input) {
            for (;;) {
                switch (input.current()) {
                case ' ':
                case '\t':
                case '\r':
                case '\n':
                    input.move();
                    continue;
                case '/':
                    switch (input.next()) {
                    case '*':
                        input.move();  // skip '/'
                        for (;;) {
                            input.move();
                            if (input.current() == '\0') return;
                            if (input.current() == '*' && input.next() == '/') {
                                input.move();  // skip '*'
                                input.move();  // skip '/'
                                break;
                            }
                        }
                        break;
                    case '/':
                        for (;;) {
                            input.move();
                            if (input.current() == '\0') return;
                            if (input.current() == '\n') break;
                        }
                        break;
                    default:
                        return;
                    }
                    break;
                default:
                    return;
                }
            }
        }
    }  // namespace Internals
}  // namespace ArduinoJson
template <typename TReader, typename TWriter>
inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::eat(
    TReader &reader, char charToSkip) {
    skipSpacesAndComments(reader);
    if (reader.current() != charToSkip) return false;
    reader.move();
    return true;
}
template <typename TReader, typename TWriter>
inline bool
ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingTo(
    JsonVariant *destination) {
    skipSpacesAndComments(_reader);
    switch (_reader.current()) {
    case '[':
        return parseArrayTo(destination);
    case '{':
        return parseObjectTo(destination);
    default:
        return parseStringTo(destination);
    }
}
template <typename TReader, typename TWriter>
inline ArduinoJson::JsonArray &
ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArray() {
    if (_nestingLimit == 0) return JsonArray::invalid();
    _nestingLimit--;
    JsonArray &array = _buffer->createArray();
    if (!eat('[')) goto ERROR_MISSING_BRACKET;
    if (eat(']')) goto SUCCESS_EMPTY_ARRAY;
    for (;;) {
        JsonVariant value;
        if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE;
        if (!array.add(value)) goto ERROR_NO_MEMORY;
        if (eat(']')) goto SUCCES_NON_EMPTY_ARRAY;
        if (!eat(',')) goto ERROR_MISSING_COMMA;
    }
SUCCESS_EMPTY_ARRAY:
SUCCES_NON_EMPTY_ARRAY:
    _nestingLimit++;
    return array;
ERROR_INVALID_VALUE:
ERROR_MISSING_BRACKET:
ERROR_MISSING_COMMA:
ERROR_NO_MEMORY:
    return JsonArray::invalid();
}
template <typename TReader, typename TWriter>
inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArrayTo(
    JsonVariant *destination) {
    JsonArray &array = parseArray();
    if (!array.success()) return false;
    *destination = array;
    return true;
}
template <typename TReader, typename TWriter>
inline ArduinoJson::JsonObject &
ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObject() {
    if (_nestingLimit == 0) return JsonObject::invalid();
    _nestingLimit--;
    JsonObject &object = _buffer->createObject();
    if (!eat('{')) goto ERROR_MISSING_BRACE;
    if (eat('}')) goto SUCCESS_EMPTY_OBJECT;
    for (;;) {
        const char *key = parseString();
        if (!key) goto ERROR_INVALID_KEY;
        if (!eat(':')) goto ERROR_MISSING_COLON;
        JsonVariant value;
        if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE;
        if (!object.set(key, value)) goto ERROR_NO_MEMORY;
        if (eat('}')) goto SUCCESS_NON_EMPTY_OBJECT;
        if (!eat(',')) goto ERROR_MISSING_COMMA;
    }
SUCCESS_EMPTY_OBJECT:
SUCCESS_NON_EMPTY_OBJECT:
    _nestingLimit++;
    return object;
ERROR_INVALID_KEY:
ERROR_INVALID_VALUE:
ERROR_MISSING_BRACE:
ERROR_MISSING_COLON:
ERROR_MISSING_COMMA:
ERROR_NO_MEMORY:
    return JsonObject::invalid();
}
template <typename TReader, typename TWriter>
inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObjectTo(
    JsonVariant *destination) {
    JsonObject &object = parseObject();
    if (!object.success()) return false;
    *destination = object;
    return true;
}
template <typename TReader, typename TWriter>
inline const char *
ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseString() {
    typename RemoveReference<TWriter>::type::String str = _writer.startString();
    skipSpacesAndComments(_reader);
    char c = _reader.current();
    if (isQuote(c)) {  // quotes
        _reader.move();
        char stopChar = c;
        for (;;) {
            c = _reader.current();
            if (c == '\0') break;
            _reader.move();
            if (c == stopChar) break;
            if (c == '\\') {
                c = Encoding::unescapeChar(_reader.current());
                if (c == '\0') break;
                _reader.move();
            }
            str.append(c);
        }
    }
    else {  // no quotes
        for (;;) {
            if (!canBeInNonQuotedString(c)) break;
            _reader.move();
            str.append(c);
            c = _reader.current();
        }
    }
    return str.c_str();
}
template <typename TReader, typename TWriter>
inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseStringTo(
    JsonVariant *destination) {
    bool hasQuotes = isQuote(_reader.current());
    const char *value = parseString();
    if (value == NULL) return false;
    if (hasQuotes) {
        *destination = value;
    }
    else {
        *destination = RawJson(value);
    }
    return true;
}
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4522)
#endif
namespace ArduinoJson {
    namespace Internals {
        class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
        public:
            FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index)
                : _array(array), _index(index) {}
            FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& src) {
                _array.set(_index, src);
                return *this;
            }
            template <typename T>
            FORCE_INLINE JsonArraySubscript& operator=(const T& src) {
                _array.set(_index, src);
                return *this;
            }
            template <typename T>
            FORCE_INLINE JsonArraySubscript& operator=(T* src) {
                _array.set(_index, src);
                return *this;
            }
            FORCE_INLINE bool success() const {
                return _index < _array.size();
            }
            template <typename T>
            FORCE_INLINE typename JsonVariantAs<T>::type as() const {
                return _array.get<T>(_index);
            }
            template <typename T>
            FORCE_INLINE bool is() const {
                return _array.is<T>(_index);
            }
            template <typename TValue>
            FORCE_INLINE bool set(const TValue& value) {
                return _array.set(_index, value);
            }
            template <typename TValue>
            FORCE_INLINE bool set(TValue* value) {
                return _array.set(_index, value);
            }
            template <typename TValue>
            DEPRECATED("Second argument is not supported anymore")
                FORCE_INLINE bool set(const TValue& value, uint8_t) {
                return _array.set(_index, value);
            }
        private:
            JsonArray& _array;
            const size_t _index;
        };
        template <typename TImpl>
        inline JsonArraySubscript JsonVariantSubscripts<TImpl>::operator[](
            size_t index) {
            return impl()->template as<JsonArray>()[index];
        }
        template <typename TImpl>
        inline const JsonArraySubscript JsonVariantSubscripts<TImpl>::operator[](
            size_t index) const {
            return impl()->template as<JsonArray>()[index];
        }
#if ARDUINOJSON_ENABLE_STD_STREAM
        inline std::ostream& operator<<(std::ostream& os,
            const JsonArraySubscript& source) {
            return source.printTo(os);
        }
#endif
    }  // namespace Internals
    inline Internals::JsonArraySubscript JsonArray::operator[](size_t index) {
        return Internals::JsonArraySubscript(*this, index);
    }
    inline const Internals::JsonArraySubscript JsonArray::operator[](
        size_t index) const {
        return Internals::JsonArraySubscript(*const_cast<JsonArray*>(this), index);
    }
}  // namespace ArduinoJson
#ifdef _MSC_VER
#pragma warning(pop)
#endif
namespace ArduinoJson {
    inline JsonArray &JsonArray::createNestedArray() {
        if (!_buffer) return JsonArray::invalid();
        JsonArray &array = _buffer->createArray();
        add(array);
        return array;
    }
    inline JsonObject &JsonArray::createNestedObject() {
        if (!_buffer) return JsonObject::invalid();
        JsonObject &object = _buffer->createObject();
        add(object);
        return object;
    }
}  // namespace ArduinoJson
inline ArduinoJson::JsonArray &ArduinoJson::JsonBuffer::createArray() {
    JsonArray *ptr = new (this) JsonArray(this);
    return ptr ? *ptr : JsonArray::invalid();
}
inline ArduinoJson::JsonObject &ArduinoJson::JsonBuffer::createObject() {
    JsonObject *ptr = new (this) JsonObject(this);
    return ptr ? *ptr : JsonObject::invalid();
}
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4522)
#endif
namespace ArduinoJson {
    namespace Internals {
        template <typename TStringRef>
        class JsonObjectSubscript
            : public JsonVariantBase<JsonObjectSubscript<TStringRef> > {
            typedef JsonObjectSubscript<TStringRef> this_type;
        public:
            FORCE_INLINE JsonObjectSubscript(JsonObject& object, TStringRef key)
                : _object(object), _key(key) {}
            FORCE_INLINE this_type& operator=(const this_type& src) {
                _object.set(_key, src);
                return *this;
            }
            template <typename TValue>
            FORCE_INLINE typename EnableIf<!IsArray<TValue>::value, this_type&>::type
                operator=(const TValue& src) {
                _object.set(_key, src);
                return *this;
            }
            template <typename TValue>
            FORCE_INLINE this_type& operator=(TValue* src) {
                _object.set(_key, src);
                return *this;
            }
            FORCE_INLINE bool success() const {
                return _object.containsKey(_key);
            }
            template <typename TValue>
            FORCE_INLINE typename JsonVariantAs<TValue>::type as() const {
                return _object.get<TValue>(_key);
            }
            template <typename TValue>
            FORCE_INLINE bool is() const {
                return _object.is<TValue>(_key);
            }
            template <typename TValue>
            FORCE_INLINE typename EnableIf<!IsArray<TValue>::value, bool>::type set(
                const TValue& value) {
                return _object.set(_key, value);
            }
            template <typename TValue>
            FORCE_INLINE bool set(const TValue* value) {
                return _object.set(_key, value);
            }
            template <typename TValue>
            DEPRECATED("Second argument is not supported anymore")
                FORCE_INLINE bool set(const TValue& value, uint8_t) {
                return _object.set(_key, value);
            }
        private:
            JsonObject& _object;
            TStringRef _key;
        };
#if ARDUINOJSON_ENABLE_STD_STREAM
        template <typename TStringRef>
        inline std::ostream& operator<<(std::ostream& os,
            const JsonObjectSubscript<TStringRef>& source) {
            return source.printTo(os);
        }
#endif
    }  // namespace Internals
}  // namespace ArduinoJson
#ifdef _MSC_VER
#pragma warning(pop)
#endif
namespace ArduinoJson {
    template <typename TStringRef>
    inline JsonArray &JsonObject::createNestedArray_impl(TStringRef key) {
        if (!_buffer) return JsonArray::invalid();
        JsonArray &array = _buffer->createArray();
        set(key, array);
        return array;
    }
    template <typename TStringRef>
    inline JsonObject &JsonObject::createNestedObject_impl(TStringRef key) {
        if (!_buffer) return JsonObject::invalid();
        JsonObject &object = _buffer->createObject();
        set(key, object);
        return object;
    }
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        inline bool isdigit(char c) {
            return '0' <= c && c <= '9';
        }
        inline bool issign(char c) {
            return '-' == c || c == '+';
        }
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        inline bool isFloat(const char* s) {
            if (!s) return false;
            if (!strcmp(s, "NaN")) return true;
            if (issign(*s)) s++;
            if (!strcmp(s, "Infinity")) return true;
            if (*s == '\0') return false;
            while (isdigit(*s)) s++;
            if (*s == '.') {
                s++;
                while (isdigit(*s)) s++;
            }
            if (*s == 'e' || *s == 'E') {
                s++;
                if (issign(*s)) s++;
                if (!isdigit(*s)) return false;
                while (isdigit(*s)) s++;
            }
            return *s == '\0';
        }
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        inline bool isInteger(const char* s) {
            if (!s || !*s) return false;
            if (issign(*s)) s++;
            while (isdigit(*s)) s++;
            return *s == '\0';
        }
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        inline T parseFloat(const char* s) {
            typedef FloatTraits<T> traits;
            typedef typename traits::mantissa_type mantissa_t;
            typedef typename traits::exponent_type exponent_t;
            if (!s) return 0;  // NULL
            bool negative_result = false;
            switch (*s) {
            case '-':
                negative_result = true;
                s++;
                break;
            case '+':
                s++;
                break;
            }
            if (*s == 't') return 1;  // true
            if (*s == 'n' || *s == 'N') return traits::nan();
            if (*s == 'i' || *s == 'I')
                return negative_result ? -traits::inf() : traits::inf();
            mantissa_t mantissa = 0;
            exponent_t exponent_offset = 0;
            while (isdigit(*s)) {
                if (mantissa < traits::mantissa_max / 10)
                    mantissa = mantissa * 10 + (*s - '0');
                else
                    exponent_offset++;
                s++;
            }
            if (*s == '.') {
                s++;
                while (isdigit(*s)) {
                    if (mantissa < traits::mantissa_max / 10) {
                        mantissa = mantissa * 10 + (*s - '0');
                        exponent_offset--;
                    }
                    s++;
                }
            }
            int exponent = 0;
            if (*s == 'e' || *s == 'E') {
                s++;
                bool negative_exponent = false;
                if (*s == '-') {
                    negative_exponent = true;
                    s++;
                }
                else if (*s == '+') {
                    s++;
                }
                while (isdigit(*s)) {
                    exponent = exponent * 10 + (*s - '0');
                    if (exponent + exponent_offset > traits::exponent_max) {
                        if (negative_exponent)
                            return negative_result ? -0.0f : 0.0f;
                        else
                            return negative_result ? -traits::inf() : traits::inf();
                    }
                    s++;
                }
                if (negative_exponent) exponent = -exponent;
            }
            exponent += exponent_offset;
            T result = traits::make_float(static_cast<T>(mantissa), exponent);
            return negative_result ? -result : result;
        }
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    namespace Internals {
        template <typename T>
        T parseInteger(const char *s) {
            if (!s) return 0;  // NULL
            if (*s == 't') return 1;  // "true"
            T result = 0;
            bool negative_result = false;
            switch (*s) {
            case '-':
                negative_result = true;
                s++;
                break;
            case '+':
                s++;
                break;
            }
            while (isdigit(*s)) {
                result = T(result * 10 + T(*s - '0'));
                s++;
            }
            return negative_result ? T(~result + 1) : result;
        }
    }  // namespace Internals
}  // namespace ArduinoJson
namespace ArduinoJson {
    inline JsonVariant::JsonVariant(const JsonArray &array) {
        if (array.success()) {
            _type = Internals::JSON_ARRAY;
            _content.asArray = const_cast<JsonArray *>(&array);
        }
        else {
            _type = Internals::JSON_UNDEFINED;
            _content.asArray = 0;  // <- prevent warning 'maybe-uninitialized'
        }
    }
    inline JsonVariant::JsonVariant(const JsonObject &object) {
        if (object.success()) {
            _type = Internals::JSON_OBJECT;
            _content.asObject = const_cast<JsonObject *>(&object);
        }
        else {
            _type = Internals::JSON_UNDEFINED;
            _content.asObject = 0;  // <- prevent warning 'maybe-uninitialized'
        }
    }
    inline JsonArray &JsonVariant::variantAsArray() const {
        if (_type == Internals::JSON_ARRAY) return *_content.asArray;
        return JsonArray::invalid();
    }
    inline JsonObject &JsonVariant::variantAsObject() const {
        if (_type == Internals::JSON_OBJECT) return *_content.asObject;
        return JsonObject::invalid();
    }
    template <typename T>
    inline T JsonVariant::variantAsInteger() const {
        using namespace Internals;
        switch (_type) {
        case JSON_UNDEFINED:
            return 0;
        case JSON_POSITIVE_INTEGER:
        case JSON_BOOLEAN:
            return T(_content.asInteger);
        case JSON_NEGATIVE_INTEGER:
            return T(~_content.asInteger + 1);
        case JSON_STRING:
        case JSON_UNPARSED:
            return parseInteger<T>(_content.asString);
        default:
            return T(_content.asFloat);
        }
    }
    inline const char *JsonVariant::variantAsString() const {
        using namespace Internals;
        if (_type == JSON_UNPARSED && _content.asString &&
            !strcmp("null", _content.asString))
            return NULL;
        if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString;
        return NULL;
    }
    template <typename T>
    inline T JsonVariant::variantAsFloat() const {
        using namespace Internals;
        switch (_type) {
        case JSON_UNDEFINED:
            return 0;
        case JSON_POSITIVE_INTEGER:
        case JSON_BOOLEAN:
            return static_cast<T>(_content.asInteger);
        case JSON_NEGATIVE_INTEGER:
            return -static_cast<T>(_content.asInteger);
        case JSON_STRING:
        case JSON_UNPARSED:
            return parseFloat<T>(_content.asString);
        default:
            return static_cast<T>(_content.asFloat);
        }
    }
    inline bool JsonVariant::variantIsBoolean() const {
        using namespace Internals;
        if (_type == JSON_BOOLEAN) return true;
        if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
        return !strcmp(_content.asString, "true") ||
            !strcmp(_content.asString, "false");
    }
    inline bool JsonVariant::variantIsInteger() const {
        using namespace Internals;
        return _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER ||
            (_type == JSON_UNPARSED && isInteger(_content.asString));
    }
    inline bool JsonVariant::variantIsFloat() const {
        using namespace Internals;
        return _type == JSON_FLOAT || _type == JSON_POSITIVE_INTEGER ||
            _type == JSON_NEGATIVE_INTEGER ||
            (_type == JSON_UNPARSED && isFloat(_content.asString));
    }
#if ARDUINOJSON_ENABLE_STD_STREAM
    inline std::ostream &operator<<(std::ostream &os, const JsonVariant &source) {
        return source.printTo(os);
    }
#endif
}  // namespace ArduinoJson
template <typename Writer>
inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
    const JsonArray& array, Writer& writer) {
    writer.beginArray();
    JsonArray::const_iterator it = array.begin();
    while (it != array.end()) {
        serialize(*it, writer);
        ++it;
        if (it == array.end()) break;
        writer.writeComma();
    }
    writer.endArray();
}
template <typename Writer>
inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
    const JsonArraySubscript& arraySubscript, Writer& writer) {
    serialize(arraySubscript.as<JsonVariant>(), writer);
}
template <typename Writer>
inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
    const JsonObject& object, Writer& writer) {
    writer.beginObject();
    JsonObject::const_iterator it = object.begin();
    while (it != object.end()) {
        writer.writeString(it->key);
        writer.writeColon();
        serialize(it->value, writer);
        ++it;
        if (it == object.end()) break;
        writer.writeComma();
    }
    writer.endObject();
}
template <typename Writer>
template <typename TKey>
inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
    const JsonObjectSubscript<TKey>& objectSubscript, Writer& writer) {
    serialize(objectSubscript.template as<JsonVariant>(), writer);
}
template <typename Writer>
inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
    const JsonVariant& variant, Writer& writer) {
    switch (variant._type) {
    case JSON_FLOAT:
        writer.writeFloat(variant._content.asFloat);
        return;
    case JSON_ARRAY:
        serialize(*variant._content.asArray, writer);
        return;
    case JSON_OBJECT:
        serialize(*variant._content.asObject, writer);
        return;
    case JSON_STRING:
        writer.writeString(variant._content.asString);
        return;
    case JSON_UNPARSED:
        writer.writeRaw(variant._content.asString);
        return;
    case JSON_NEGATIVE_INTEGER:
        writer.writeRaw('-');  // Falls through.
    case JSON_POSITIVE_INTEGER:
        writer.writeInteger(variant._content.asInteger);
        return;
    case JSON_BOOLEAN:
        writer.writeBoolean(variant._content.asInteger != 0);
        return;
    default:  // JSON_UNDEFINED
        return;
    }
}
#ifdef __GNUC__
#define ARDUINOJSON_PRAGMA(x) _Pragma(#x)
#define ARDUINOJSON_COMPILE_ERROR(msg) ARDUINOJSON_PRAGMA(GCC error msg)
#define ARDUINOJSON_STRINGIFY(S) #S
#define ARDUINOJSON_DEPRECATION_ERROR(X, Y) \
  ARDUINOJSON_COMPILE_ERROR(ARDUINOJSON_STRINGIFY(X is a Y from ArduinoJson 6 but version 5 is installed. Visit arduinojson.org to get more information.))
#define StaticJsonDocument ARDUINOJSON_DEPRECATION_ERROR(StaticJsonDocument, class)
#define DynamicJsonDocument ARDUINOJSON_DEPRECATION_ERROR(DynamicJsonDocument, class)
#define JsonDocument ARDUINOJSON_DEPRECATION_ERROR(JsonDocument, class)
#define DeserializationError ARDUINOJSON_DEPRECATION_ERROR(DeserializationError, class)
#define deserializeJson ARDUINOJSON_DEPRECATION_ERROR(deserializeJson, function)
#define deserializeMsgPack ARDUINOJSON_DEPRECATION_ERROR(deserializeMsgPack, function)
#define serializeJson ARDUINOJSON_DEPRECATION_ERROR(serializeJson, function)
#define serializeMsgPack ARDUINOJSON_DEPRECATION_ERROR(serializeMsgPack, function)
#define serializeJsonPretty ARDUINOJSON_DEPRECATION_ERROR(serializeJsonPretty, function)
#define measureMsgPack ARDUINOJSON_DEPRECATION_ERROR(measureMsgPack, function)
#define measureJson ARDUINOJSON_DEPRECATION_ERROR(measureJson, function)
#define measureJsonPretty ARDUINOJSON_DEPRECATION_ERROR(measureJsonPretty, function)
#endif

using namespace ArduinoJson;

#else

#error ArduinoJson requires a C++ compiler, please change file extension to .cc or .cpp

#endif
